package entity_message

import (
	"chat_gin/entity/models"
	"encoding/json"
	"fmt"
	"github.com/gorilla/websocket"
	"gopkg.in/fatih/set.v0"
	"net"
	"net/http"
	"strconv"
	"sync"
)

type Node struct {
	Conn      *websocket.Conn
	DataQueue chan []byte
	GroupSets set.Interface
}

// 映射关系
var clientMap map[int64]*Node = make(map[int64]*Node, 0)

// 读写锁
var rwLocker sync.RWMutex

func Chat(writer http.ResponseWriter, request *http.Request) {
	// 1 获取用户信息,并 校验token 等合法性
	//token := query.Get("token")
	query := request.URL.Query()
	userId, _ := strconv.Atoi(query.Get("user_id"))
	//targetId := query.Get("target_id")
	//context := query.Get("context")
	//msgType := query.Get("type")
	isvalida := true // check token
	conn, err := (&websocket.Upgrader{
		CheckOrigin: func(r *http.Request) bool {
			return isvalida
		},
	}).Upgrade(writer, request, nil)
	if err != nil {
		fmt.Println("连接错误", err)
		return
	}
	// 2 获取 conn
	node := &Node{
		Conn:      conn,
		DataQueue: make(chan []byte, 50),
		GroupSets: set.New(set.ThreadSafe),
	}

	// 3  用户关系判断

	// 4 user_id 和 node 绑定并加锁
	rwLocker.Lock()
	clientMap[int64(userId)] = node
	rwLocker.Unlock()
	// 5 完成发送逻辑
	go sendProc(node)
	// 6 完成接收逻辑
	go recvProc(node)
	// 进入系统以后默认欢迎话语
	sendMsg(int64(userId), []byte("欢迎"))
}

func sendProc(node *Node) {
	for {
		select {
		case data := <-node.DataQueue:
			err := node.Conn.WriteMessage(websocket.TextMessage, data)
			if err != nil {
				fmt.Println("发送消息失败", err)
			}
		}
	}
}

// 接收消息
func recvProc(node *Node) {
	for {
		_, data, err := node.Conn.ReadMessage()
		if err != nil {
			fmt.Println("接收消息失败", err)
			return
		}
		// 消息要广播到局域网
		broadMsg(data)
		fmt.Println("[ws]发送的消息", data)
	}
}

// 定义一个管道用消息
var udpsendChan chan []byte = make(chan []byte, 1024)

// 消息要广播到局域网
func broadMsg(data []byte) {
	// 把消息放进管道
	udpsendChan <- data
}

// 这里需要初始化的协程,用于收发消息
func init() {
	go udpSendProc()
	go udpRecvProc()
}

// 完成udp数据发送协程
func udpSendProc() {
	con, err := net.DialUDP("udp", nil, &net.UDPAddr{
		IP:   net.IPv4(192, 168, 124, 1), // TODO 这里后面要修改
		Port: 3000,
	})
	if err != nil {
		fmt.Println(err)
		return
	}
	defer func(con *net.UDPConn) {
		err := con.Close()
		if err != nil {
			fmt.Println("关闭udp错误", err)
		}
	}(con)
	for {
		select {
		case data := <-udpsendChan:
			_, err := con.Write(data)
			if err != nil {
				fmt.Println("写入失败", err)
				return
			}
		}
	}
}

// 完成udp数据接收协程
func udpRecvProc() {
	con, err := net.ListenUDP("udp", &net.UDPAddr{
		IP:   net.IPv4zero,
		Port: 3000,
	})
	if err != nil {
		fmt.Println(err)
		return
	}
	defer func(con *net.UDPConn) {
		err := con.Close()
		if err != nil {
			fmt.Println(err)
		}
	}(con)
	for {
		var buf [512]byte
		n, err := con.Read(buf[0:]) // 读取数据从0-n
		if err != nil {
			fmt.Println(err)
			return
		}
		dispatch(buf[0:n])
	}
}

// 后端调度的逻辑
func dispatch(data []byte) {
	msg := models.Message{}
	err := json.Unmarshal(data, &msg)
	if err != nil {
		fmt.Println(err)
		return
	}
	switch msg.Type {
	case 1:
		// 这里第一个参数是消息接受者的id
		sendMsg(msg.TargetId, []byte(msg.Content))
		break
	case 2:
		sendGroupMsg()
		break
	case 3:
		sendAllMsg()
		break
	default:

		break

	}
}

// 发送消息,这里只是首次调用
func sendMsg(userId int64, msg []byte) {
	rwLocker.RLock()
	node, ok := clientMap[userId]
	rwLocker.RUnlock()
	fmt.Println("显示发送的消息", msg)
	if ok {
		node.DataQueue <- msg
	}
}

func sendGroupMsg() {

}

func sendAllMsg() {

}
